/* Copyright 2017 The Apollo Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
=========================================================================*/
#ifndef MODULES_MAP_HDMAP_ADAPTER_ODR_PARSER_UTIL_ODR_PARSER_H_
#define MODULES_MAP_HDMAP_ADAPTER_ODR_PARSER_UTIL_ODR_PARSER_H_

#include <string>
#include <vector>

#include "tinyxml2/tinyxml2.h"

#include "modules/map/hdmap/adapter/xml_parser/common_define.h"
#include "modules/map/hdmap/adapter/xml_parser/status.h"

#include "modules/map/hdmap/adapter/odr_parser/data_define.h"

#include "modules/map/hdmap/adapter/odr_parser/roadengine_api.h"

namespace apollo {
namespace hdmap {
namespace adapter {

class UtilOdrParser {
public:
  enum LaneType {
    LEFT_LANE,
    RIGHT_LANE,
    CENTER_LANE
  };

  enum LaneBoundaryType {
    LEFT_BOUNDARY,
    RIGHT_BOUNDARY,
    CENTER
  };

  static void BoundaryToCurve(PbCurve* boundary_curve, const rg::LaneDivRefLine& refLine,
                                    const glm::dvec3& origin, double s, double e,
                                    bool reverse = false);
  static void CenterToCurve(PbCurve* curve,
                                  const rg::LaneDivRefLine& refLine,
                                  const glm::dvec3& origin, double s, double e,
                                  bool reverse = false);

  static void ToCurve(const PlanView& planview, double s, double e, double offset,
                           PbCurve* curve, bool reverseXAxis);

  static void SetPointSet(Geometry* geometry, double s, double e,
                          double offset, PbLineSegment* line_segment,
                          bool reverseXAxis);
  static ESpeedUnitType ToSpeedUnit(const std::string& unit);

  static void AddPoint(glm::dmat3x3& uv2xy, glm::dvec3& P0,
                             const Lane& lane,
                             const std::vector<Lane*>& lanes_between_center,
                             double cur_s,
                             PbLineSegment* center_line_segment,
                             PbLineSegment* far_line_segment,
                             PbLineSegment* near_line_segment,
                             LaneType lane_type,
                             bool reverseXAxis);
  static void SetFirstPoint(PbCurveSegment* center_curve_segment,
                            PbLineSegment* line_segment);
  static double GetLaneWidth(const Lane& lane, double s);
  static double GetLaneBorder(const Lane& lane, double s);

  static void ToStopLineCurve(const PlanView& planview, double s, 
	                                double u1, double u2,
									                PbCurveSegment* curve_segment,
									                bool reverseXAxis);
  static void SetPointSetByOffset(Geometry* geometry, double s, 
                          double u0, double u1, PbLineSegment* line_segment,
                          bool reverseXAxis);
  static void ToLightPolygon(const PlanView& planview, double s, 
	                           PbPolygon* polygon,
									           bool reverseXAxis);

  static Road* FindRoad(const std::map<std::string, Road*>& roads,
                          const std::string& roadId);                     
  static const LaneInternal* GetLaneInRoad(const RoadInternal* road_internal, const std::string& lane_id);
  static apollo::common::PointENU GetStartPointOfLane(const LaneInternal* lane_internal,
                                                       LaneBoundaryType side);
  static apollo::common::PointENU GetEndPointOfLane(const LaneInternal* lane_internal,
                                                       LaneBoundaryType side);
  static void MegerPointsInSameLine(const std::vector<apollo::common::PointENU>& sorted_points,
                                          std::vector<apollo::common::PointENU>& merged_points);

  static double Interpolate(double prev, double next, double lambda) {
    return (1 - lambda) * prev + lambda * next;
  }
  static void ST2XY(const PlanView& planview, double s, double t, double& x, double& y);
  static void cornerLocalToGlobal(const ObjectOutline& outline, double hdg, double x, double y, PbPolygon* polygon);
  static double CurveResolution;

private:
  static void AddPoint(glm::dmat3x3& uv2xy, glm::dvec3& P0, 
                             PbLineSegment* line_segment, bool reverseXAxis);
  static void AddTrafficLightPolygonPoints(const glm::dmat3x3& uv2xy, const glm::dvec3& P0, 
                                            PbPolygon* polygon, bool reverseXAxis);
  static const PbCurve& GetLaneCurve(const LaneInternal* lane_internal,
                                       LaneBoundaryType side); 
  static bool PointsInSameLine(const std::vector<apollo::common::PointENU>& points,
                                     size_t first, size_t second);                                                                   
};

}  // namespace adapter
}  // namespace hdmap
}  // namespace apollo

#endif  // MODULES_MAP_HDMAP_ADAPTER_XML_PARSER_UTIL_XML_PARSER_H_
